package com.example.train.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.example.train.common.config.security.model.AuthUserDetail;
import com.example.train.model.SysAdminRoleRelation;
import com.example.train.model.SysRole;
import com.example.train.model.request.SysAdminLoginRequest;
import com.example.train.model.SysAdmin;
import com.example.train.service.SysAdminRoleRelationService;
import com.example.train.service.SysAdminService;
import com.example.train.service.SysRoleService;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import com.example.train.mapper.SysAdminMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SysAdminServiceImpl implements SysAdminService {

    @Resource
    private SysAdminMapper sysAdminMapper;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysAdminRoleRelationService sysAdminRoleRelationService;

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public int deleteByPrimaryKey(Long id) {
        sysAdminRoleRelationService.deleteByAdminId(id);
        return sysAdminMapper.deleteByPrimaryKey(id);
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Integer insert(SysAdmin record) {
        SysAdmin temp = sysAdminMapper.selectByUsername(record.getUsername());
        if (temp != null) {
            return null;
        }
        record.setCreateTime(new Date());
        String encodePassword = passwordEncoder.encode(record.getPassword());
        record.setPassword(encodePassword);
        record.setTokenSalt(BCrypt.gensalt());

        int count = sysAdminMapper.insert(record);

        if (CollUtil.isNotEmpty(record.getRoles())) {
            handleRoleInsert(record);
        }

        return count;
    }

    @Override
    public int insertSelective(SysAdmin record) {
        return sysAdminMapper.insertSelective(record);
    }

    @Override
    public SysAdmin selectByPrimaryKey(Long id, boolean noPwd) {
        SysAdmin sysAdmin = sysAdminMapper.selectByPrimaryKey(id);
        if (noPwd) {
            sysAdmin.setPassword(null);
            sysAdmin.setTokenSalt(null);
        }
        return sysAdmin;
    }

    @Override
    public SysAdmin selectByUsername(String username) {
        return sysAdminMapper.selectByUsername(username);
    }

    @Override
    public List<SysAdmin> selectAll(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<SysAdmin> list = sysAdminMapper.selectAll();
        for (SysAdmin sysAdmin : list) {
            List<SysRole> roles = sysRoleService.selectByAdminID(sysAdmin.getId());
            sysAdmin.setRoles(roles);
        }
        return list;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public int updateByPrimaryKeySelective(SysAdmin record) {

        List<SysAdminRoleRelation> relations = sysAdminRoleRelationService.selectByAdminIdsAndRoleIds(Collections.singletonList(record.getId()), null);
        List<SysRole> roles = record.getRoles();
        if (CollUtil.isNotEmpty(relations)) {
            for (SysAdminRoleRelation relation : relations) {
                boolean present = roles.stream().anyMatch(l -> l.getId().equals(relation.getRoleId()));
                if (!present) {
                    sysAdminRoleRelationService.deleteById(relation.getId());
                }
            }

            if (CollUtil.isNotEmpty(roles)) {
                //新增role保存，过滤已经存在的，不再保存
                List<SysAdminRoleRelation> collect = roles.stream()
                        .filter(r -> relations.stream().noneMatch(l -> l.getRoleId().equals(r.getId())))
                        .map(l -> new SysAdminRoleRelation(record.getId(), l.getId()))
                        .collect(Collectors.toList());

                if (CollUtil.isNotEmpty(collect)) {
                    sysAdminRoleRelationService.insert(collect);
                }
            }
        }else{
            handleRoleInsert(record);
        }
        SysAdmin recordCopy = new SysAdmin();
        BeanUtils.copyProperties(record,recordCopy, "username","password","tokenSalt","createTime","loginTime");
        return sysAdminMapper.updateByPrimaryKeySelective(recordCopy);
    }

    @Override
    public int updateByPrimaryKey(SysAdmin record) {
        return sysAdminMapper.updateByPrimaryKey(record);
    }

    @Override
    public SysAdmin login(SysAdminLoginRequest param) throws AccountStatusException {
        String username = param.getUsername();
        AuthUserDetail userDetails = (AuthUserDetail) userDetailsService.loadUserByUsername(username);
        SysAdmin sysAdmin = userDetails.getSysAdmin();
        if (!userDetails.canUse()) {
            throw new DisabledException("账号处于不可用状态");
        }

        if (!passwordEncoder.matches(param.getPassword(), userDetails.getPassword())) {
            throw new BadCredentialsException("用户名或密码不正确");
        }
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        //记录登录时间 todo 日志记录
//        sysAdmin.setLoginTime(new Date());
//        updateByPrimaryKeySelective(sysAdmin);
        sysAdmin.setRoles(userDetails.getRoleList());
        return sysAdmin;
    }

    /**
     * 主要是增加角色，前端限制一次只能为单个角色关联多个用户
     * @param param
     * @return
     */
    @Override
    public int updateMultiAdminRole(List<SysAdminRoleRelation> param) {
        List<Long> adminIds = param.stream().map(SysAdminRoleRelation::getAdminId).collect(Collectors.toList());
        List<SysAdminRoleRelation> relations = sysAdminRoleRelationService.selectByAdminIdsAndRoleIds(adminIds, Collections.singletonList(param.get(0).getRoleId()));

        List<SysAdminRoleRelation> collect = param.stream().filter(p ->
                relations.stream().noneMatch(r -> p.getAdminId().equals(r.getAdminId())))
                .collect(Collectors.toList());

        if (CollUtil.isNotEmpty(collect)) {
            return sysAdminRoleRelationService.insert(collect);
        }
        return 0;
    }

    private void handleRoleInsert(SysAdmin record){
        if (CollUtil.isNotEmpty(record.getRoles())) {
            List<SysAdminRoleRelation> collect = record.getRoles().stream()
                    .map(l -> new SysAdminRoleRelation(record.getId(),l.getId()))
                    .collect(Collectors.toList());
            sysAdminRoleRelationService.insert(collect);
        }
    }
}
